package com.jiaming.restaurant.api.common.controller;

import com.jiaming.restaurant.api.common.exception.ApiException;
import com.jiaming.restaurant.api.common.response.ResultCode;
import com.jiaming.restaurant.api.common.response.ResultCodeEnum;
import com.jiaming.restaurant.api.common.response.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.HashMap;
import java.util.Map;

/**
 * @author dragon
 * @create 2020-12-18 16:35
 */
@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice {
    //1.请求参数类型错误，比如要求传入字段类型是整型，但传入的是字符串
    //2.请求方法错误，比如要求是POST请求，但执行的是GET请求
    //3.请求参数必填项错误，比如FORM表单要求必传某个字段但没有传入
    //4.请求内容类型错误，比如要求传入的内容是JSON类型，但传入的是TEXT类型
    //5.请求内容为空，比如请求时没有传入JSON内容
    //6.请求内容是JSON格式的参数安全效验 使用@Valid 如果效验失败需要处理的异常
    //7.业务异常统一处理

    //业务异常统一处理
    @ExceptionHandler({ApiException.class})
    public ResultVo<String> apiExceptionHandler(ApiException e){
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.BIZ_DAIL,e.getDatail());
//        return new ResultVo<>(e.getCode(),e.getMsg(),e.getDatail());
    }


    //请求内容是JSON格式的参数安全效验 使用@Valid 如果效验失败需要处理的异常
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResultVo<String> methodArgumentNotValidExceptionHanler(
            MethodArgumentNotValidException e){
        // 从异常对象中拿到ObjectError 对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        //然后提取错误提示信息进行返回
        String errorMessage = objectError.getDefaultMessage();
        log.warn("警告信息 :{}",errorMessage);
        //返回错误码，并在data中存放具体参数效验失败原因
        return new ResultVo<>(ResultCodeEnum.FAIL_PARAM_VALIDATE,errorMessage);
    }


    // 请求参数必填项错误，比如FORM表单要求必传某个字段但没有传入
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ResultVo<String> missingServletRequestParameterExceptionHandler(
            MissingServletRequestParameterException e) {
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.FAIL_PARAM_MISSING,e.getLocalizedMessage());
    }


    // 请求方法错误，比如要求是POST请求，但执行的是GET请求
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResultVo<String> httpRequestMethodNotSupportedExceptionHanler(
            HttpRequestMethodNotSupportedException e){
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.FAIL_REQUEST_METHOD,e.getLocalizedMessage());
    }


    // 请求参数类型错误，比如要求传入字段类型是整型，但传入的是字符串
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public ResultVo<String> methodArgumentTypeMismatchExceptionHandler(
            MethodArgumentTypeMismatchException e) {
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.FAIL_PARAM_TYPE,e.getLocalizedMessage());
    }


    // 请求内容类型错误，比如要求传入的内容是JSON类型，但传入的是TEXT类型
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public ResultVo<String> httpMediaTypeNotSupportedException(
            HttpMediaTypeNotSupportedException e){
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.FAIL_REQUEST_TYPE,e.getLocalizedMessage());
    }

    // 请求内容为空，比如请求时没有传入JSON内容
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ResultVo<String> httpMessageNotReadableException(
            HttpMessageNotReadableException e){
        log.error("警告错误:{}",e.getLocalizedMessage());
        return new ResultVo<>(ResultCodeEnum.FAIL_REQUEST_CONTENT,e.getLocalizedMessage());
    }


    // 以上处理器不能处理的异常都会被该处理器处理
    @ExceptionHandler
    public Object exceptionHandler(Exception e) {
        e.printStackTrace();
        String message = e.getClass().getName() + "|" + e.getLocalizedMessage();
        log.error("未知错误: {}" + message);
        return new ResultVo<>(ResultCodeEnum.FAIL,message);
    }
}
